package org.jeecg.common.util;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.poi.ss.formula.functions.T;
import org.jeecg.common.util.util_entity.core.PageCondition;
import org.jeecg.common.util.util_entity.core.PageResult;
import org.jeecg.common.util.util_entity.core.TableDataInfo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.Optional.ofNullable;

/**
 * 分页工具类
 *
 * @author addzero
 * @since 2022/5/4 11:37 AM
 */
@SuppressWarnings("unused")
public class PageUtils2 {

    /**
     * 分页api割接得到所有列表
     *
     * @param limitSize 限制大小
     * @param inBO      入参业务BO
     * @param convert   转换
     * @param api       api
     * @return 返回信息
     * @author zjarlin
     * @since 2022/06/06
     */
    public static <In, ApiOut, ApiIn extends PageCondition> List<ApiOut> getAllListFromTab(final int limitSize,
                                                                                           In inBO,
                                                                                           Function<In, ApiIn> convert,
                                                                                           Function<ApiIn, TableDataInfo<ApiOut>> api) {
        final ApiIn apiIn = convert.apply(inBO);
        List<ApiOut> ret = new ArrayList<>();
        for (int initPageNum = 1; ; initPageNum++) {
            apiIn.setPageNum(initPageNum);
            final TableDataInfo<ApiOut> result = api.apply(apiIn);
            final List<ApiOut> searchList = ofNullable(result).map(TableDataInfo::getContent).orElseGet(ArrayList::new);
            if (CollUtil.isEmpty(searchList)) {
                break;
                //如果查出来有东西,但是不足限制大小,加进去
            } else if (searchList.size() < limitSize) {
                ret.addAll(searchList);
                break;
            }
            //走到这说明等于限制大小,下页必有数据,加进去接着循环
            ret.addAll(searchList);
        }
        return ret;
    }

    /**
     * 分页api割接得到所有列表
     *
     * @param limitSize 每次只能查几个
     * @param inBO      入参业务BO
     * @param convert   转换
     * @param api       api
     * @return 返回信息
     * @author zjarlin
     * @since 2022/06/06
     */
    public static <In, ApiOut, ApiIn extends PageCondition> List<ApiOut> getAllListFromPageRes(final int limitSize,
                                                                                               In inBO,
                                                                                               Function<In, ApiIn> convert,
                                                                                               Function<ApiIn, PageResult<ApiOut>> api) {
        final ApiIn apiIn = convert.apply(inBO);
        return getAllListFromPageRes(limitSize, apiIn, api);
    }

    public static <In, ApiOut, ApiIn extends PageCondition> List<ApiOut> getAllListFromPageRes(final int limitSize,
                                                                                               ApiIn apiIn,
                                                                                               Function<ApiIn, PageResult<ApiOut>> api) {
        List<ApiOut> ret = new ArrayList<>();
        apiIn.setPageNum(1);
        apiIn.setPageSize(limitSize);
        final PageResult<ApiOut> body = api.apply(apiIn);
        final Integer total = ofNullable(body).map(PageResult::getTotal).orElse(null);
        //如果对方返回了total,走下面方法节省算力
        if (Objects.nonNull(total)) {
            return getAllListFromPageResWithTotal(limitSize, apiIn, api);
        }

        for (int initPageNum = 1; ; initPageNum++) {
            apiIn.setPageNum(initPageNum);
            final PageResult<ApiOut> result = api.apply(apiIn);
            final List<ApiOut> searchList = ofNullable(result).map(PageResult::getData).orElseGet(ArrayList::new);
            if (CollUtil.isEmpty(searchList)) {
                break;
                //如果查出来有东西,但是不足限制大小,加进去
            } else if (searchList.size() < limitSize) {
                ret.addAll(searchList);
                break;
            }
            //走到这说明等于限制大小,下页必有数据,加进去接着循环
            ret.addAll(searchList);
        }
        return ret;
    }


    public static <In, ApiOut, ApiIn extends PageCondition> List<ApiOut> getAllListFromPageResWithTotal(final int limitSize,
                                                                                                        ApiIn apiIn,
                                                                                                        Function<ApiIn, PageResult<ApiOut>> api) {
        int initPageNum = 1;
        apiIn.setPageNum(initPageNum);
        apiIn.setPageSize(limitSize);
        //先查一次
        final PageResult<ApiOut> result = api.apply(apiIn);
        final PageResult<ApiOut> body = result;
        final int total = ofNullable(body).map(PageResult::getTotal).orElse(0);
        List<ApiOut> ret = new ArrayList<>(ofNullable(body).map(PageResult::getData).orElseGet(Collections::emptyList));
        if (total < limitSize) {
            return ret;
        }
        //条数除以限制向上取整(即调用分页的次数)
        final double ceil = Math.ceil((double) total / limitSize);

        for (int nextPageNum = 2; nextPageNum <= ceil; nextPageNum++) {
            apiIn.setPageNum(nextPageNum);
            final PageResult<ApiOut> bodynext = api.apply(apiIn);
            final List<ApiOut> data = ofNullable(bodynext.getData()).orElseGet(Collections::emptyList);
            ret.addAll(data);
        }
        ret.removeIf(Objects::isNull);
        return ret;
    }


    public Page<T> list2Page(List<T> list, Integer pageNum, Integer pageSize) {
        final List<T> data = list.stream().skip((long) (Math.max(1, pageNum) - 1) * pageSize).limit(pageSize).collect(Collectors.toList());
        final int totals = list.size();
        //总页数
        final int page = (totals + pageSize - 1) / pageSize;
        return new Page<T>(pageNum, pageSize) {{
            setPages(page);
            setRecords(data);
            setTotal(totals);
        }};
    }

}
